/*
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//          Copyright(c) 2003-2008 Intel Corporation. All Rights Reserved.
//
//     Intel(R) Integrated Performance Primitives AAC Decode Sample for Windows*
//
//  By downloading and installing this sample, you hereby agree that the
//  accompanying Materials are being provided to you under the terms and
//  conditions of the End User License Agreement for the Intel(R) Integrated
//  Performance Primitives product previously accepted by you. Please refer
//  to the file ippEULA.rtf or ippEULA.txt located in the root directory of your Intel(R) IPP
//  product installation for more information.
//
//  MPEG-4 and AAC are international standards promoted by ISO, IEC, ITU, ETSI
//  and other organizations. Implementations of these standards, or the standard
//  enabled platforms may require licenses from various entities, including
//  Intel Corporation.
//
*/

#include "umc_defs.h"

#if defined (UMC_ENABLE_AAC_INT_AUDIO_DECODER)

#include <stdlib.h>
#include "aac_dec_int.h"
#include "aac_dec_decoding_int.h"
#include "aac_dec_own_int.h"
#include "aac_dec_huff_tables_int.h"
#include "sbr_huff_tabs.h"
#include "sbr_dec_api_int.h"
#include "sbr_dec_tabs_int.h"

/********************************************************************/

AACStatus aacidecReset(AACDec *state)
{
  Ipp32s i;

  if (!state)
    return AAC_NULL_PTR;

  state->com.decodedBytes = 0;
  state->com.m_frame_number = 0;
  state->com.m_index_1st = 0;
  state->com.m_index_2nd = 1;
  state->com.m_index_3rd = 2;

  state->com.noiseState = 0;
  state->com.SbrFlagPresent = 0;

  /* set default params: (HQ, DWNSMPL_ON, SBR_ENABLE) */
  //------------------------------------------------------------
  if( HEAAC_PARAMS_UNDEF == state->com.ModeDecodeHEAACprofile){
    state->com.ModeDecodeHEAACprofile = HEAAC_HQ_MODE;
  }

  if ( HEAAC_PARAMS_UNDEF == state->com.ModeDwnsmplHEAACprofile ) {
    state->com.ModeDwnsmplHEAACprofile  = HEAAC_DWNSMPL_ON;
  }

  if (SBR_UNDEF == state->com.m_flag_SBR_support_lev) {
    state->com.m_flag_SBR_support_lev   = SBR_ENABLE;
  }
  //------------------------------------------------------------

  for (i = 0; i < CH_MAX + COUPL_CH_MAX; i++) {
    ippsZero_16s(state->m_ltp_buf[i][0], 2048);
    ippsZero_16s(state->m_ltp_buf[i][1], 2048);
    ippsZero_16s(state->m_ltp_buf[i][2], 2048);
    ippsZero_32s(state->m_prev_samples[i], 2048);
    state->com.m_prev_win_shape[i] = 0;
  }

  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecGetSize(Ipp32s *pStateSize)
{
  Ipp32s  i;
  /* HE-AAC */
  Ipp32s mStateSize;
  Ipp32s pSize[12], mSize;
  Ipp32s pSbrSize[10], mSbrSize;
  Ipp32s mOneFilterSize, mFilterSize;
  Ipp32s pOneFilterSize[7];
  Ipp32s mSBRDecSize;

  /* aligned size of AACDec */
  mStateSize = __ALIGNED(sizeof(AACDec));

  /* size of huffman_tables */
  mSize = 0;
  for (i = 0; i < 12; i++) {
    if ((aacidec_vlcTypes[i] != 3) && (aacidec_vlcTypes[i] != 4)) {
      if(ippsVLCDecodeGetSize_32s(aacidec_vlcBooks[i],
                                  aacidec_vlcTableSizes[i],
                                  aacidec_vlcSubTablesSizes[i],
                                  aacidec_vlcNumSubTables[i],
                                  &(pSize[i])) != ippStsOk) {
        return AAC_ALLOC;
      } else {
        pSize[i] = __ALIGNED(pSize[i]);
        mSize += pSize[i];
      }
    } else {
      if(ippsVLCDecodeUTupleGetSize_32s(aacidec_vlcBooks[i],
                                        aacidec_vlcTableSizes[i],
                                        aacidec_vlcSubTablesSizes[i],
                                        aacidec_vlcNumSubTables[i],
                                        aacidec_vlcTuples[i],
                                        aacidec_vlcShifts[i],
                                        &(pSize[i])) != ippStsOk) {
        return AAC_ALLOC;
      } else {
        pSize[i] = __ALIGNED(pSize[i]);
        mSize += pSize[i];
      }
    }
  }

  /* size of sbrHuffTables */
  mSbrSize = 0;
  for (i = 0; i < 10; i++) {
    if (ippsVLCDecodeGetSize_32s(vlcSbrBooks[i],
                                 vlcSbrTableSizes[i],
                                 vlcSbrSubTablesSizes[i],
                                 vlcSbrNumSubTables[i],
                                 &(pSbrSize[i])) != ippStsOk) {
      return AAC_ALLOC;
    } else {
      pSbrSize[i] = __ALIGNED(pSbrSize[i]);
      mSbrSize += pSbrSize[i];
    }
  }

  if (sbridecGetFilterSize(pOneFilterSize))
    return AAC_ALLOC;
  mOneFilterSize = pOneFilterSize[0] + pOneFilterSize[0];
  mOneFilterSize += pOneFilterSize[1] + pOneFilterSize[1];
  mFilterSize = __ALIGNED(mOneFilterSize * CH_MAX + SBR_MINSIZE_OF_WORK_BUFFER);

  sbriDecoderGetSize(&mSBRDecSize);

  pStateSize[0] = mStateSize + mSize + mSbrSize +
                  mFilterSize + mSBRDecSize;

  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecInit(AACDec *state)
{
  Ipp32s  i;
  /* HE-AAC */
  Ipp32s mStateSize;
  Ipp32s pSize[12], mSize;
  Ipp32s pSbrSize[10], mSbrSize;
  Ipp8u *pMem;
  Ipp32s mOneFilterSize, mFilterSize;
  Ipp32s pOneFilterSize[2];
  sSbrDecFilter* sbr_filter[CH_MAX];
  sSBRBlock* sbrBlock[CH_MAX];

  if (!state)
    return AAC_NULL_PTR;

  for (i = 0; i < CH_MAX; i++) {
    sbr_filter[i] = &(state->sbr_filter[i]);
    sbrBlock[i] = &(state->sbrBlock[i]);
  }

  /* aligned size of AACDec */
  mStateSize = __ALIGNED(sizeof(AACDec));

  /* size of huffman_tables */
  mSize = 0;
  for (i = 0; i < 12; i++) {
    if ((aacidec_vlcTypes[i] != 3) && (aacidec_vlcTypes[i] != 4)) {
      if(ippsVLCDecodeGetSize_32s(aacidec_vlcBooks[i],
                                  aacidec_vlcTableSizes[i],
                                  aacidec_vlcSubTablesSizes[i],
                                  aacidec_vlcNumSubTables[i],
                                  &(pSize[i])) != ippStsOk) {
        return AAC_ALLOC;
      } else {
        pSize[i] = __ALIGNED(pSize[i]);
        mSize += pSize[i];
      }
    } else {
      if(ippsVLCDecodeUTupleGetSize_32s(aacidec_vlcBooks[i],
                                        aacidec_vlcTableSizes[i],
                                        aacidec_vlcSubTablesSizes[i],
                                        aacidec_vlcNumSubTables[i],
                                        aacidec_vlcTuples[i],
                                        aacidec_vlcShifts[i],
                                        &(pSize[i])) != ippStsOk) {
        return AAC_ALLOC;
      } else {
        pSize[i] = __ALIGNED(pSize[i]);
        mSize += pSize[i];
      }
    }
  }

  /* size of sbrHuffTables */
  mSbrSize = 0;
  for (i = 0; i < 10; i++) {
    if (ippsVLCDecodeGetSize_32s(vlcSbrBooks[i],
                                 vlcSbrTableSizes[i],
                                 vlcSbrSubTablesSizes[i],
                                 vlcSbrNumSubTables[i],
                                 &(pSbrSize[i])) != ippStsOk) {
      return AAC_ALLOC;
    } else {
      pSbrSize[i] = __ALIGNED(pSbrSize[i]);
      mSbrSize += pSbrSize[i];
    }
  }

  if (sbridecGetFilterSize(pOneFilterSize))
    return AAC_ALLOC;
  mOneFilterSize = pOneFilterSize[0] + pOneFilterSize[0];
  mOneFilterSize += pOneFilterSize[1] + pOneFilterSize[1];
  mFilterSize = __ALIGNED(mOneFilterSize * CH_MAX + SBR_MINSIZE_OF_WORK_BUFFER);

  /* important: here HEAAC params must be UNDEF */

  state->com.ModeDecodeHEAACprofile = HEAAC_PARAMS_UNDEF;
  state->com.ModeDwnsmplHEAACprofile  = HEAAC_PARAMS_UNDEF;
  state->com.m_flag_SBR_support_lev = SBR_UNDEF;

  aacidecReset(state);

  state->com.FirstID3Search = 0;
  state->com.id3_size = 0;

  state->com.m_is_chmap_valid = 0;
  state->com.m_is_pce_valid = 0;
  state->com.m_sampling_frequency = 0;
  state->com.m_sampling_frequency_index = 0;
  state->com.m_channel_number = 1;
  state->com.m_channel_number_save = 1;
  state->com.m_channel_number_all = 0;
  state->com.m_element_number = 0;
  state->com.m_channel_config = 0;
  state->com.m_frame_size = 1024;
  state->com.adts_channel_configuration = -1;

  state->com.m_audio_object_type = AOT_UNDEF;

  for (i = 0; i < 16; i++) {
    state->com.huffman_tables[i] = NULL;
  }

  for (i = 0; i < 10; i++) {
    state->com.sbrHuffTables[i] = NULL;
  }

  state->pWorkBuffer = NULL;

  pMem = (Ipp8u *)state + mStateSize;
  for (i = 0; i < 12; i++) {
    if ((aacidec_vlcTypes[i] != 3) && (aacidec_vlcTypes[i] != 4)) {
      state->com.huffman_tables[i] = pMem;
      if (ippsVLCDecodeInit_32s(aacidec_vlcBooks[i],
                                aacidec_vlcTableSizes[i],
                                aacidec_vlcSubTablesSizes[i],
                                aacidec_vlcNumSubTables[i],
                                state->com.huffman_tables[i]) != ippStsOk) {
        return AAC_ALLOC;
      } else {
        pSize[i] = __ALIGNED(pSize[i]);
        pMem += pSize[i];
      }
    } else {
      state->com.huffman_tables[i] = pMem;
      if (ippsVLCDecodeUTupleInit_32s(aacidec_vlcBooks[i],
                                      aacidec_vlcTableSizes[i],
                                      aacidec_vlcSubTablesSizes[i],
                                      aacidec_vlcNumSubTables[i],
                                      aacidec_vlcTuples[i],
                                      aacidec_vlcShifts[i],
                                      state->com.huffman_tables[i]) != ippStsOk) {
        return AAC_ALLOC;
      } else {
        pSize[i] = __ALIGNED(pSize[i]);
        pMem += pSize[i];
      }

    }
  }

  for (i = 0; i < 10; i++) {
    state->com.sbrHuffTables[i] = (IppsVLCDecodeSpec_32s *)pMem;
    if(ippsVLCDecodeInit_32s(vlcSbrBooks[i],
                             vlcSbrTableSizes[i],
                             vlcSbrSubTablesSizes[i],
                             vlcSbrNumSubTables[i],
                             state->com.sbrHuffTables[i]) != ippStsOk) {
      return AAC_ALLOC;
    } else {
      pSbrSize[i] = __ALIGNED(pSbrSize[i]);
      pMem += pSbrSize[i];
    }
  }

  (state->com.m_sce).stream.p_huffman_tables = (void **)&(state->com.huffman_tables[0]);
  (state->com.m_cpe).streams[0].p_huffman_tables = (void **)&(state->com.huffman_tables[0]);
  (state->com.m_cpe).streams[1].p_huffman_tables = (void **)&(state->com.huffman_tables[0]);
  (state->com.m_cce).stream.p_huffman_tables = (void **)&(state->com.huffman_tables[0]);
  (state->com.m_lfe).stream.p_huffman_tables = (void **)&(state->com.huffman_tables[0]);

  (state->com.m_sce).stream.vlcShifts = aacidec_vlcShifts;
  (state->com.m_cpe).streams[0].vlcShifts = aacidec_vlcShifts;
  (state->com.m_cpe).streams[1].vlcShifts = aacidec_vlcShifts;
  (state->com.m_cce).stream.vlcShifts = aacidec_vlcShifts;
  (state->com.m_lfe).stream.vlcShifts = aacidec_vlcShifts;

  (state->com.m_sce).stream.vlcOffsets = aacidec_vlcOffsets;
  (state->com.m_cpe).streams[0].vlcOffsets = aacidec_vlcOffsets;
  (state->com.m_cpe).streams[1].vlcOffsets = aacidec_vlcOffsets;
  (state->com.m_cce).stream.vlcOffsets = aacidec_vlcOffsets;
  (state->com.m_lfe).stream.vlcOffsets = aacidec_vlcOffsets;

  (state->com.m_sce).stream.vlcTypes = aacidec_vlcTypes;
  (state->com.m_cpe).streams[0].vlcTypes = aacidec_vlcTypes;
  (state->com.m_cpe).streams[1].vlcTypes = aacidec_vlcTypes;
  (state->com.m_cce).stream.vlcTypes = aacidec_vlcTypes;
  (state->com.m_lfe).stream.vlcTypes = aacidec_vlcTypes;

  sbridecDrawMemMap(sbr_filter, pMem, pOneFilterSize);
  state->pWorkBuffer = pMem + mOneFilterSize * CH_MAX;

  if (sbridecInitFilter(state))
    return AAC_ALLOC;

  pMem += mFilterSize;
  sbriInitDecoder(sbrBlock, pMem);

  for (i = 0; i < CH_MAX; i++) {
    ippsCopy_8u((const Ipp8u *)(state->com.sbrHuffTables),
      (Ipp8u *)(state->sbrBlock[i].comState.sbrHuffTables), 10 * sizeof(void *));
  }

  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecUpdateStateMemMap(AACDec *state, Ipp32s mShift)
{
  Ipp32s  i;
  sSbrDecFilter* sbr_filter[CH_MAX];

  if (!state)
    return AAC_NULL_PTR;

  for (i = 0; i < CH_MAX; i++) {
    sbr_filter[i] = &(state->sbr_filter[i]);
  }

  for (i = 0; i < 16; i++) {
    AACDEC_UPDATE_PTR(void, state->com.huffman_tables[i], mShift)
  }
  for (i = 0; i < 10; i++) {
    AACDEC_UPDATE_PTR(IppsVLCDecodeSpec_32s, state->com.sbrHuffTables[i], mShift)
  }

  AACDEC_UPDATE_PTR(Ipp8u, state->pWorkBuffer, mShift)

  (state->com.m_sce).stream.p_huffman_tables = (void **)&(state->com.huffman_tables[0]);
  (state->com.m_cpe).streams[0].p_huffman_tables = (void **)&(state->com.huffman_tables[0]);
  (state->com.m_cpe).streams[1].p_huffman_tables = (void **)&(state->com.huffman_tables[0]);
  (state->com.m_cce).stream.p_huffman_tables = (void **)&(state->com.huffman_tables[0]);
  (state->com.m_lfe).stream.p_huffman_tables = (void **)&(state->com.huffman_tables[0]);

  sbridecUpdateMemMap(sbr_filter, mShift);

  return AAC_OK;
}

/********************************************************************/

#define RETURN_AAC_BAD_STREAM                                     \
{                                                                 \
  GET_BITS_COUNT(pBS, (*decodedBytes))                            \
  *decodedBytes = (*decodedBytes + 7) >> 3;                       \
  state_com->m_channel_number = state_com->m_channel_number_save; \
  state_com->m_is_chmap_valid = save_m_is_chmap_valid;            \
  state_com->m_is_pce_valid = save_m_is_pce_valid;                \
  return AAC_BAD_STREAM;                                          \
}

/********************************************************************/

static Ipp32s aacGetChannel(Ipp32s id,
                            Ipp32s tag,
                            Ipp32s element_number,
                            sEl_map_item elmap[])
{
  Ipp32s i;
  for (i = 0; i < element_number; i++) {
    if ((elmap[i].id == id) && (elmap[i].tag == tag)) {
      return elmap[i].ch;
    }
  }
  return -1;
}

/********************************************************************/

AACStatus aacidecGetFrame(Ipp8u  *inPointer,
                          Ipp32s *decodedBytes,
                          Ipp16s *outPointer,
                          Ipp32s inDataSize,
                          Ipp32s outBufferSize,
                          AACDec *state)
{
  sData_stream_element m_data;
  sDynamic_range_info m_drc_info;
  sEl_map_item m_elmap[EL_TAG_MAX];

  sBitsreamBuffer BS;
  sBitsreamBuffer *pBS = &BS;
  AACDec_com      *state_com;

  Ipp32s  el_num;
  Ipp32s  ch_num;
  Ipp32s  order_counter = 0;
  Ipp32s  cur_frame_el_num = 0;
  Ipp32s  save_m_is_chmap_valid;
  Ipp32s  save_m_is_pce_valid;

  Ipp32s  id;
  Ipp32s  tag = 0;
  Ipp32s  ch = 0;
  Ipp32s  ncch = 0;
  Ipp32s  tag_counter[4][EL_TAG_MAX];

/* HE-AAC param */
  Ipp32s  cnt_fill_sbr_element = 0;
  Ipp32s  cnt_idaac_sbr_element = 0;
  Ipp32s  sbrFlagPresentLFE = 0;
  Ipp32s  NumRealCh = 0;
  Ipp32s  ch_counter;
  Ipp32s  scaleFactorCoreAAC;
  Ipp32s  scaleFactorAAC;
  Ipp32s  errSBRParser = 0;

  s_tns_data tns_data0;
  Ipp32s  i, j, m_channel_number, decodedBits;

  if (!inPointer || !outPointer)
    return AAC_NULL_PTR;

  for (i = 0; i < 4; i++) {
    for (j = 0; j < EL_TAG_MAX; j++) {
      tag_counter[i][j] = 0;
    }
  }

  state_com = &(state->com);
  el_num = state_com->m_element_number;
  ch_num = state_com->m_channel_number_all;

  save_m_is_chmap_valid = state_com->m_is_chmap_valid;
  save_m_is_pce_valid = state_com->m_is_pce_valid;

  /* state_com->decodedBytes != 0 means that this frame   */
  /* has been decoded already but output buffer was small */
  if (state_com->decodedBytes == 0) {

    GET_INIT_BITSTREAM(pBS, inPointer)

    // init
    state->com.m_up_sample  = 1;

    GET_BITS(pBS, id, 3, Ipp32s)
    while (id != ID_END) {
      if (CH_MAX - 1 < NumRealCh)
        RETURN_AAC_BAD_STREAM;
      switch (id) {
      case ID_SCE:
        /* may be there is HE-AAC element */
      state->sbrBlock[cnt_idaac_sbr_element++].comState.id_aac = ID_SCE;
        NumRealCh++;

        /* Parsing bitstream */
        (state_com->m_sce).crc = state_com->crc;
        (state_com->m_sce).crc_enable = state_com->crc_enable;
        if (dec_sce_channel_element(&(state_com->m_sce), pBS, state_com->m_audio_object_type) < 0)
          RETURN_AAC_BAD_STREAM;
        state_com->crc = (state_com->m_sce).crc;
        tag = (state_com->m_sce).element_instance_tag;
        /* several equal tags are supported */
        tag_counter[0][tag] += 1;
        tag += ((tag_counter[0][tag] - 1) * EL_TAG_MAX);
        break;
      case ID_CPE:
        /* may be there is HE-AAC element */
      state->sbrBlock[cnt_idaac_sbr_element++].comState.id_aac = ID_CPE;
        NumRealCh += 2;

        /* Parsing bitstream */
        (state_com->m_cpe).crc = state_com->crc;
        (state_com->m_cpe).crc_enable = state_com->crc_enable;
        if (dec_cpe_channel_element(&(state_com->m_cpe), pBS, state_com->m_audio_object_type) < 0)
          RETURN_AAC_BAD_STREAM;
        state_com->crc = (state_com->m_cpe).crc;
        tag = (state_com->m_cpe).element_instance_tag;
        /* several equal tags are supported */
        tag_counter[1][tag] += 1;
        tag += ((tag_counter[1][tag] - 1) * EL_TAG_MAX);
        break;
      case ID_CCE:
        if (COUPL_CH_MAX - 1 < ncch)
          RETURN_AAC_BAD_STREAM;

        (state_com->m_cce).crc = state_com->crc;
        (state_com->m_cce).crc_enable = state_com->crc_enable;
        if (dec_coupling_channel_element(&(state_com->m_cce), &(state_com->m_cdata[ncch]),
              pBS, state_com->m_audio_object_type) < 0)
          RETURN_AAC_BAD_STREAM;
        state_com->crc = (state_com->m_cce).crc;
        tag = (state_com->m_cce).element_instance_tag;
        /* several equal tags are supported */
        tag_counter[2][tag] += 1;
        tag += ((tag_counter[2][tag] - 1) * EL_TAG_MAX);
        break;
      case ID_LFE:
        /* may be there is HE-AAC element */
        if (CH_MAX - 1 < cnt_idaac_sbr_element)
          RETURN_AAC_BAD_STREAM;

      state->sbrBlock[cnt_idaac_sbr_element++].comState.id_aac = ID_LFE;

        if (cnt_fill_sbr_element > 0) {
          sbrFlagPresentLFE++;

          if ( CH_MAX - 1 < cnt_fill_sbr_element )
            RETURN_AAC_BAD_STREAM;

          cnt_fill_sbr_element++;
        }

        /* Parsing bitstream */
        (state_com->m_lfe).crc = state_com->crc;
        (state_com->m_lfe).crc_enable = state_com->crc_enable;
        if (dec_lfe_channel_element(&(state_com->m_lfe), pBS, state_com->m_audio_object_type) < 0)
          RETURN_AAC_BAD_STREAM;
        state_com->crc = (state_com->m_lfe).crc;
        tag = (state_com->m_lfe).element_instance_tag;
        /* several equal tags are supported */
        tag_counter[3][tag] += 1;
        tag += ((tag_counter[3][tag] - 1) * EL_TAG_MAX);
        NumRealCh++;
        break;
      case ID_DSE:
        dec_data_stream_element(&m_data, pBS);
        break;
      case ID_PCE:
        {
          Ipp32u  *crc_ptr = 0;
          Ipp32s  crc_offset = 0;
          Ipp32s  decodedBits0 = 0;
          Ipp32s  decodedBits2 = 0;

          if (state_com->crc_enable) {
            crc_ptr = pBS->pCurrent_dword;
            crc_offset = pBS->nBit_offset;
            GET_BITS_COUNT(pBS, decodedBits0)
          }

          dec_program_config_element(&(state_com->m_pce), pBS);

          if (state_com->crc_enable) {
            Ipp32u crc = (Ipp32u)state_com->crc;
            GET_BITS_COUNT(pBS, decodedBits2)
              bs_CRC_update(crc_ptr, crc_offset, decodedBits2 - decodedBits0, &crc);
            state_com->crc = (Ipp32s)crc;
          }
          state_com->m_is_chmap_valid = 0;
          state_com->m_is_pce_valid = 1;
        }
        break;
      case ID_FIL:
/*
* NOTES:
* (1)SBR FILL ELEMENT there is for SCE & CPE modes only.
* (2)If AOT AAC is MAIN, LC or LTP
* then
*   <SCE> <FIL <EXT_SBR_DATA(SCE)>> // center
*   <CPE> <FIL <EXT_SBR_DATA(CPE)>> // front L/R
*   <CPE> <FIL <EXT_SBR_DATA(CPE)>> // back L/R
*   <LFE> // sub
*   <END> // (end of raw data block)
*
* (3)If AOT AAC is ER LC or ER LTP
* then
*   <SCE> <CPE> <CPE> <LFE> <EXT <SBR(SCE)> <SBR(CPE)> <SBR(CPE)>>
*
* (4) may be more then one FILL ELEMENT, for ex:
*  <SCE> <FILL.. <CPE> <FILL.. <CPE> <FILL..><FILL..> <LFE><FILL..><FILL..><FILL..>
*/
        if ( CH_MAX - 1 < cnt_fill_sbr_element )
          RETURN_AAC_BAD_STREAM;

      state->sbrBlock[cnt_fill_sbr_element].comState.sbr_freq_sample =
          state_com->m_sampling_frequency * 2;

        if (state->com.m_sampling_frequency_index >= 3)
        state->sbrBlock[cnt_fill_sbr_element].comState.sbr_freq_indx =
            state->com.m_sampling_frequency_index - 3;

      /* AYA: move to parser */
      //state->sbrBlock[cnt_fill_sbr_element]->comState.sbrFlagError = 0;

      errSBRParser = dec_fill_element(&(state->sbrBlock[cnt_fill_sbr_element].comState),
                                       &cnt_fill_sbr_element, &m_drc_info, pBS, SBR_ENABLE);

        /* patch while fixed point sbr isn't implemented
        {
        sSBRDecComState SbrBlock;
        dec_fill_element(&SbrBlock, &cnt_fill_sbr_element, &m_drc_info, pBS);
        }
        */

        /*************************************************************
        * if there is problem with HE-AAC parser then QUIT
        *************************************************************/
        if ( errSBRParser )
          RETURN_AAC_BAD_STREAM

        break;
      }

      /* robustness */
      GET_BITS_COUNT(pBS, decodedBits)
      if (decodedBits > inDataSize * 8) {
        RETURN_AAC_BAD_STREAM;
      }

      if ((ID_DSE > id) && (ID_CCE != id)) {
        ch = aacGetChannel(id, tag, el_num, state_com->m_elmap);

        m_elmap[cur_frame_el_num].id = (Ipp16s)id;
        m_elmap[cur_frame_el_num].tag = (Ipp16s)tag;
        m_elmap[cur_frame_el_num].ch = (Ipp16s)ch;

        if (ch < 0) {
          if (el_num >= CH_MAX)
            RETURN_AAC_BAD_STREAM
          state_com->m_elmap[el_num].id = (Ipp16s)id;
          state_com->m_elmap[el_num].tag = (Ipp16s)tag;
          state_com->m_elmap[el_num].ch = (Ipp16s)ch_num;
          ch = ch_num;
          el_num++;
          ch_num++;
          if (ID_CPE == id) ch_num++;
        }

        m_elmap[cur_frame_el_num].id = (Ipp16s)id;
        m_elmap[cur_frame_el_num].tag = (Ipp16s)tag;
        m_elmap[cur_frame_el_num].ch = (Ipp16s)ch;

        cur_frame_el_num++;

        state_com->m_order[order_counter] = ch;
        order_counter++;

        if (ch >= CH_MAX)
          RETURN_AAC_BAD_STREAM

        if (ID_CPE == id) {
          state_com->m_order[order_counter] = ch+1;
          order_counter++;
          if (ch+1 >= CH_MAX)
            RETURN_AAC_BAD_STREAM
        }
      }

      switch (id) {
      case ID_SCE:

        state_com->m_curr_win_shape[ch] = (state_com->m_sce).stream.window_shape;
        state_com->m_curr_win_sequence[ch] = (state_com->m_sce).stream.window_sequence;

        if (0 != (state_com->m_sce).stream.pulse_data_present) {
          ics_apply_pulse_I(&(state_com->m_sce).stream);
        }

        aacidec_ics_apply_scale_factors(&(state_com->m_sce).stream, state->m_spectrum_data[ch]);

        aacidec_apply_pns(&(state_com->m_sce).stream, NULL, state->m_spectrum_data[ch], NULL, 1,
                  0, NULL, &(state_com->noiseState));

        aacidec_deinterlieve(&(state_com->m_sce).stream, state->m_spectrum_data[ch]);
        aacidec_ics_calc_tns_data(&(state_com->m_sce).stream, &(state->tns_data[ch]));

        if (AOT_AAC_LTP == state_com->m_audio_object_type) {
          state->m_ltp.p_samples_1st_part = state->m_ltp_buf[ch][state_com->m_index_1st];
          state->m_ltp.p_samples_2nd_part = state->m_ltp_buf[ch][state_com->m_index_2nd];
          state->m_ltp.p_samples_3rd_part = state->m_ltp_buf[ch][state_com->m_index_3rd];
          state->m_ltp.prev_windows_shape = state_com->m_prev_win_shape[ch];

          state->m_ltp.p_tns_data = &(state->tns_data[ch]);

          aacidec_ics_apply_ltp_I(&(state->m_ltp), &(state_com->m_sce).stream, state->m_spectrum_data[ch]);
        }
        break;
      case ID_CPE:

        state_com->m_curr_win_shape[ch] = (state_com->m_cpe).streams[0].window_shape;
        state_com->m_curr_win_sequence[ch] = (state_com->m_cpe).streams[0].window_sequence;
        state_com->m_curr_win_shape[ch + 1] = (state_com->m_cpe).streams[1].window_shape;
        state_com->m_curr_win_sequence[ch + 1] = (state_com->m_cpe).streams[1].window_sequence;

        if (0 != (state_com->m_cpe).streams[0].pulse_data_present) {
          ics_apply_pulse_I(&(state_com->m_cpe).streams[0]);
        }
        if (0 != (state_com->m_cpe).streams[1].pulse_data_present) {
          ics_apply_pulse_I(&(state_com->m_cpe).streams[1]);
        }

        aacidec_ics_apply_scale_factors(&(state_com->m_cpe).streams[0], state->m_spectrum_data[ch]);
        aacidec_ics_apply_scale_factors(&(state_com->m_cpe).streams[1],
                                state->m_spectrum_data[ch + 1]);

        /* Joint stereo */
        aacidec_cpe_apply_ms(&(state_com->m_cpe), state->m_spectrum_data[ch],
                      state->m_spectrum_data[ch + 1]);

        aacidec_apply_pns(&(state_com->m_cpe).streams[0], &(state_com->m_cpe).streams[1],
                  state->m_spectrum_data[ch], state->m_spectrum_data[ch + 1], 2,
                  (state_com->m_cpe).ms_mask_present, (state_com->m_cpe).ms_used,
                  &(state_com->noiseState));

        aacidec_cpe_apply_intensity(&(state_com->m_cpe), state->m_spectrum_data[ch],
                            state->m_spectrum_data[ch + 1]);


        aacidec_ics_calc_tns_data(&(state_com->m_cpe).streams[0], &(state->tns_data[ch]));
        aacidec_ics_calc_tns_data(&(state_com->m_cpe).streams[1], &(state->tns_data[ch + 1]));

        aacidec_deinterlieve(&(state_com->m_cpe).streams[0], state->m_spectrum_data[ch]);
        aacidec_deinterlieve(&(state_com->m_cpe).streams[1], state->m_spectrum_data[ch + 1]);

        if (AOT_AAC_LTP == state_com->m_audio_object_type) {
          state->m_ltp.p_samples_1st_part = state->m_ltp_buf[ch][state_com->m_index_1st];
          state->m_ltp.p_samples_2nd_part = state->m_ltp_buf[ch][state_com->m_index_2nd];
          state->m_ltp.p_samples_3rd_part = state->m_ltp_buf[ch][state_com->m_index_3rd];
          state->m_ltp.prev_windows_shape = state_com->m_prev_win_shape[ch];

          state->m_ltp.p_tns_data = &(state->tns_data[ch]);

          aacidec_ics_apply_ltp_I(&(state->m_ltp), &(state_com->m_cpe).streams[0],
                          state->m_spectrum_data[ch]);

          state->m_ltp.p_samples_1st_part = state->m_ltp_buf[ch + 1][state_com->m_index_1st];
          state->m_ltp.p_samples_2nd_part = state->m_ltp_buf[ch + 1][state_com->m_index_2nd];
          state->m_ltp.p_samples_3rd_part = state->m_ltp_buf[ch + 1][state_com->m_index_3rd];
          state->m_ltp.prev_windows_shape = state_com->m_prev_win_shape[ch + 1];

          state->m_ltp.p_tns_data = &(state->tns_data[ch + 1]);

          aacidec_ics_apply_ltp_I(&(state->m_ltp), &(state_com->m_cpe).streams[1],
                          state->m_spectrum_data[ch + 1]);
        }
        break;
      case ID_CCE:

        state_com->m_curr_win_shape[CH_MAX + ncch] =
          (state_com->m_cce).stream.window_shape;
        state_com->m_curr_win_sequence[CH_MAX + ncch] =
          (state_com->m_cce).stream.window_sequence;

        if (0 != (state_com->m_cce).stream.pulse_data_present) {
          ics_apply_pulse_I(&(state_com->m_cce).stream);
        }

        aacidec_ics_apply_scale_factors(&(state_com->m_cce).stream,
          state->m_spectrum_data[CH_MAX + ncch]);

        aacidec_apply_pns(&(state_com->m_cce).stream, NULL,
                  state->m_spectrum_data[CH_MAX + ncch], NULL, 1,
                  0, NULL, &(state_com->noiseState));

        aacidec_deinterlieve(&(state_com->m_cce).stream,
          state->m_spectrum_data[CH_MAX + ncch]);

        aacidec_ics_calc_tns_data(&(state_com->m_cce).stream, &tns_data0);

        if (AOT_AAC_LTP == state_com->m_audio_object_type) {
          state->m_ltp.p_samples_1st_part =
            state->m_ltp_buf[CH_MAX + ncch][state_com->m_index_1st];
          state->m_ltp.p_samples_2nd_part =
            state->m_ltp_buf[CH_MAX + ncch][state_com->m_index_2nd];
          state->m_ltp.p_samples_3rd_part =
            state->m_ltp_buf[CH_MAX + ncch][state_com->m_index_3rd];
          state->m_ltp.prev_windows_shape =
            state_com->m_prev_win_shape[CH_MAX + ncch];

          state->m_ltp.p_tns_data = &tns_data0;

          aacidec_ics_apply_ltp_I(&(state->m_ltp), &(state_com->m_cce).stream,
            state->m_spectrum_data[CH_MAX + ncch]);
        }

        if (0 != tns_data0.m_tns_data_present) {
          aacidec_ics_apply_tns_dec_I(&tns_data0, state->m_spectrum_data[CH_MAX + ncch]);
        }

        aacidec_coupling_gain_calculation(&(state_com->m_cce), &(state_com->m_cdata[ncch]),
                                  state->cc_gain[ncch], state->cc_gain_factor[ncch]);
        ncch++;
        break;
      case ID_LFE:
        state_com->m_curr_win_shape[ch] = (state_com->m_lfe).stream.window_shape;
        state_com->m_curr_win_sequence[ch] = (state_com->m_lfe).stream.window_sequence;

        if (0 != (state_com->m_lfe).stream.pulse_data_present) {
          ics_apply_pulse_I(&(state_com->m_lfe).stream);
        }
        aacidec_ics_apply_scale_factors(&(state_com->m_lfe).stream, state->m_spectrum_data[ch]);
        state->tns_data[ch].m_tns_data_present = 0;
        break;
      default:
        break;
      }
      GET_BITS(pBS, id, 3, Ipp32s)
    }

    if (1 == state_com->m_is_pce_valid) {
      if (state_com->m_is_chmap_valid == 0) {
        if (chmap_create_by_pce(&(state_com->m_pce), state_com->m_chmap) < 0)
          RETURN_AAC_BAD_STREAM;
        state_com->m_is_chmap_valid = 1;
      }

      order_counter = chmap_order(state_com->m_chmap, m_elmap,
                                  cur_frame_el_num, state_com->m_order);
    } else if (state_com->adts_channel_configuration > 0) {
      if (chmap_create_by_adts(state_com->adts_channel_configuration,
          state_com->m_chmap, m_elmap, cur_frame_el_num) < 0)
          RETURN_AAC_BAD_STREAM;

      order_counter = chmap_order(state_com->m_chmap, m_elmap,
                                  cur_frame_el_num, state_com->m_order);
    }

    state_com->m_channel_number = order_counter;
    state_com->m_channel_number_all = ch_num;
    state_com->m_element_number = el_num;

    for (i = 0; i < order_counter; i++) {
      ch = state_com->m_order[i];
      state->m_ordered_samples[i] = state->m_spectrum_data[ch];
    }

    if (AOT_AAC_LTP == state_com->m_audio_object_type) {
      state_com->m_index_1st++;
      if (state_com->m_index_1st == 3)
        state_com->m_index_1st = 0;
      state_com->m_index_2nd++;
      if (state_com->m_index_2nd == 3)
        state_com->m_index_2nd = 0;
      state_com->m_index_3rd++;
      if (state_com->m_index_3rd == 3)
        state_com->m_index_3rd = 0;
    }

    /* coupling channel process */
    for (ch = 0; ch < ncch; ch++) {
      Ipp32s c;
      for (c = 0; c < state_com->m_cdata[ch].num_coupled_elements + 1; c++) {
        Ipp32s id = state_com->m_cdata[ch].cc_target_id[c];
        Ipp32s tag = state_com->m_cdata[ch].cc_target_tag[c];
        state_com->m_cdata[ch].cc_target_ch[c] =
          aacGetChannel(id, tag, state_com->m_element_number, state_com->m_elmap);
      }
    }

    scaleFactorCoreAAC = 7;

    for (ch = 0; ch < ncch; ch++) {
      if ((state_com->m_cdata[ch].ind_sw_cce_flag) ||
          (AOT_AAC_LTP == state_com->m_audio_object_type)) {

        ippsMDCTInv_AAC_32s_I(state->m_spectrum_data[CH_MAX + ch],
                              state->m_prev_samples[CH_MAX + ch],
                              state_com->m_curr_win_sequence[CH_MAX + ch],
                              state_com->m_curr_win_shape[CH_MAX + ch],
                              state_com->m_prev_win_shape[CH_MAX + ch], 1024);

        state_com->m_prev_win_shape[CH_MAX + ch] =
          state_com->m_curr_win_shape[CH_MAX + ch];

        /* Update buffers for LTP */
        if (AOT_AAC_LTP == state_com->m_audio_object_type) {
          ippsConvert_32s16s_Sfs(state->m_curr_samples[CH_MAX + ch],
                              state->m_ltp_buf[ch][state_com->m_index_2nd],
                              1024, scaleFactorCoreAAC);

          ippsConvert_32s16s_Sfs(state->m_prev_samples[CH_MAX + ch],
                                state->m_ltp_buf[ch][state_com->m_index_3rd],
                                1024, scaleFactorCoreAAC);
        }
      }
    }

    for (ch = 0; ch < ncch; ch++) {
      if ((!state_com->m_cdata[ch].ind_sw_cce_flag) &&
          (!state_com->m_cdata[ch].cc_domain)) {
      aacidec_coupling_spectrum(state, &(state_com->m_cdata[ch]),
                                state->m_spectrum_data[CH_MAX + ch],
                                state_com->m_curr_win_sequence[CH_MAX + ch],
                                state->cc_gain[ch], state->cc_gain_factor[ch]);
      }
    }

    for (i = 0; i < state_com->m_channel_number; i++) {
      ch = state_com->m_order[i];
      if (0 != state->tns_data[ch].m_tns_data_present) {
        aacidec_ics_apply_tns_dec_I(&(state->tns_data[ch]), state->m_spectrum_data[ch]);
      }
    }

    for (ch = 0; ch < ncch; ch++) {
      if ((!state_com->m_cdata[ch].ind_sw_cce_flag) &&
          (state_com->m_cdata[ch].cc_domain)) {
      aacidec_coupling_spectrum(state, &(state_com->m_cdata[ch]),
                                state->m_spectrum_data[CH_MAX + ch],
                                state_com->m_curr_win_sequence[CH_MAX + ch],
                                state->cc_gain[ch], state->cc_gain_factor[ch]);
      }
    }

    for (ch_counter = 0; ch_counter < state_com->m_channel_number; ch_counter++) {
      ch = state_com->m_order[ch_counter];

      ippsMDCTInv_AAC_32s_I(state->m_spectrum_data[ch],
                            state->m_prev_samples[ch],
                            state_com->m_curr_win_sequence[ch],
                            state_com->m_curr_win_shape[ch],
                            state_com->m_prev_win_shape[ch], 1024);

      state_com->m_prev_win_shape[ch] = state_com->m_curr_win_shape[ch];
    }

    for (ch = 0; ch < ncch; ch++) {
      if (state_com->m_cdata[ch].ind_sw_cce_flag) {
      aacidec_coupling_samples(state, &(state_com->m_cdata[ch]),
                      state->m_spectrum_data[CH_MAX + ch],
                      state->cc_gain[ch], state->cc_gain_factor[ch]);
      }
    }

    for (ch_counter = 0; ch_counter < state_com->m_channel_number; ch_counter++) {
      ch = state_com->m_order[ch_counter];

      /* Update buffers for LTP */
      if (AOT_AAC_LTP == state_com->m_audio_object_type) {
        ippsConvert_32s16s_Sfs(state->m_spectrum_data[ch],
                              state->m_ltp_buf[ch][state_com->m_index_2nd],
                              1024, scaleFactorCoreAAC);

        ippsConvert_32s16s_Sfs(state->m_prev_samples[ch],
                              state->m_ltp_buf[ch][state_com->m_index_3rd],
                              1024, scaleFactorCoreAAC);
      }
    }
      /* HE-AAC patch */
    if ((sbrFlagPresentLFE) && (cnt_fill_sbr_element)) {

      /* we passed LFE if ER AAC mode is used */
      if (cnt_fill_sbr_element != cnt_idaac_sbr_element) {
        cnt_fill_sbr_element++;
      }

      /* may be error? if yes then we isn't doing sbr process */
      if (cnt_fill_sbr_element != cnt_idaac_sbr_element) {
        cnt_fill_sbr_element = 0;
      }

    }

    // be careful !!!
    scaleFactorAAC = scaleFactorCoreAAC;

    for (i = 0, j = 0; i < cnt_fill_sbr_element; i++) {

      scaleFactorAAC = scaleFactorCoreAAC;

      sbriGetFrame(state->m_spectrum_data[j],// implace call
                   state->m_spectrum_data[j],
                   &(state->sbrBlock[i]), &(state->sbr_filter[i]),
                   0, //ch L
                   state_com->ModeDecodeHEAACprofile,
                   state_com->ModeDwnsmplHEAACprofile,
                   state->pWorkBuffer,
                   &scaleFactorAAC ); //sf will be changed

      j++;

    if (state->sbrBlock[i].comState.id_aac == ID_CPE) {


    /* we "forget" New scaleFactorAAC from L_CHANNEL
    * because OUT scaleFactor for L & R channel the same
    */

        scaleFactorAAC = scaleFactorCoreAAC;

        sbriGetFrame(state->m_spectrum_data[j],// implace call
                     state->m_spectrum_data[j],
                     &(state->sbrBlock[i]),
                     &(state->sbr_filter[i]),
                     1,//ch R
                     state_com->ModeDecodeHEAACprofile,
                     state_com->ModeDwnsmplHEAACprofile,
                     state->pWorkBuffer,
                     &scaleFactorAAC );//sf will be changed

        j++;
      }
    }

    if (cnt_fill_sbr_element) {
      if (state_com->ModeDwnsmplHEAACprofile == HEAAC_DWNSMPL_OFF) {
        state->com.m_up_sample  = 2;
      }
      state_com->SbrFlagPresent = 1;
    }
    Byte_alignment(pBS);
    GET_BITS_COUNT(pBS, (*decodedBytes))
      *decodedBytes >>= 3;
    state_com->m_channel_number_save = state_com->m_channel_number;
    state->scaleFactorAAC = scaleFactorAAC;
  } else {
    *decodedBytes = state_com->decodedBytes;
    scaleFactorAAC = state->scaleFactorAAC;
    state_com->crc = state_com->saved_crc;
  }

  if (outBufferSize < (state_com->m_channel_number *
      state->com.m_up_sample * 1024 * (Ipp32s)(sizeof(Ipp16s)))) {
    state_com->decodedBytes = *decodedBytes;
    state_com->saved_crc = state_com->crc;
    return AAC_NOT_ENOUGH_BUFFER;
  }

  m_channel_number = state_com->m_channel_number;

  if (m_channel_number == 1) {
    for (j = 0; j < m_channel_number; j++) {
      Ipp16s *tmpPtr = outPointer + j;
      Ipp32s num = state->com.m_up_sample * 1024;
      Ipp32s *srcPrt = state->m_ordered_samples[j];

      for (i = 0; i < num; i++) {
        Ipp32s tmp = *srcPrt;
        Ipp32s tmp0;
        tmp = (tmp + ( 1 << (scaleFactorAAC -1) ) ) >> scaleFactorAAC;
        tmp0 = tmp;
        if (tmp > 32767) tmp0 = 32767;
        if (tmp < -32768) tmp0 = -32768;
        *tmpPtr = (Ipp16s)tmp0;
        tmpPtr++;
        srcPrt++;
      }
    }
  } else if (m_channel_number == 2) {
    for (j = 0; j < m_channel_number; j++) {
      Ipp16s *tmpPtr = outPointer + j;
      Ipp32s num = state->com.m_up_sample * 1024;
      Ipp32s *srcPrt = state->m_ordered_samples[j];

      for (i = 0; i < num; i++) {
        Ipp32s tmp = *srcPrt;
        Ipp32s tmp0;
        tmp = (tmp + ( 1 << (scaleFactorAAC -1) ) ) >> scaleFactorAAC;
        tmp0 = tmp;
        if (tmp > 32767) tmp0 = 32767;
        if (tmp < -32768) tmp0 = -32768;
        *tmpPtr = (Ipp16s)tmp0;
        tmpPtr += 2;
        srcPrt++;
      }
    }
  } else {
    for (j = 0; j < m_channel_number; j++) {
      Ipp16s *tmpPtr = outPointer + j;
      Ipp32s num = state->com.m_up_sample * 1024;
      Ipp32s *srcPrt = state->m_ordered_samples[j];

      for (i = 0; i < num; i++) {
        Ipp32s tmp = *srcPrt;
        Ipp32s tmp0;
        tmp = (tmp + ( 1 << (scaleFactorAAC -1) ) ) >> scaleFactorAAC;
        tmp0 = tmp;
        if (tmp > 32767) tmp0 = 32767;
        if (tmp < -32768) tmp0 = -32768;
        *tmpPtr = (Ipp16s)tmp0;
        tmpPtr += m_channel_number;
        srcPrt++;
      }
    }
  }

  state_com->decodedBytes = 0;
  state_com->m_frame_number++;
  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecSetSamplingFrequency(Ipp32s sampling_frequency_index,
                                      AACDec *state)
{
  return aacdecSetSamplingFrequencyCom(sampling_frequency_index,
                                       &(state->com));
}

/********************************************************************/

AACStatus aacidecSetSBRModeDecode(Ipp32s ModeDecodeHEAAC,
                                  AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  if (state->com.ModeDecodeHEAACprofile != ModeDecodeHEAAC) {
    state->com.ModeDecodeHEAACprofile = ModeDecodeHEAAC;
    sbridecInitFilter(state);
  }

  return AAC_OK;
}


/********************************************************************/

AACStatus aacidecSetSBRModeDwnmx(Ipp32s ModeDwnsmplHEAAC,
                                 AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  state->com.ModeDwnsmplHEAACprofile = ModeDwnsmplHEAAC;

  return AAC_OK;
}


/********************************************************************/

AACStatus aacidecSetSBRSupport(eSBR_SUPPORT flag, AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  state->com.m_flag_SBR_support_lev = flag;

  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecSetAudioObjectType(enum AudioObjectType audio_object_type,
                                    AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  state->com.m_audio_object_type = audio_object_type;
  return AAC_OK;
}


/********************************************************************/

AACStatus aacidecSetPCE(sProgram_config_element *pce,
                        AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  ippsCopy_8u((Ipp8u*)pce, (Ipp8u*)(&(state->com.m_pce)),
              sizeof(sProgram_config_element));

  state->com.m_is_pce_valid = 1;

  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecSetAdtsChannelConfiguration(Ipp32s adts_channel_configuration,
                                             AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  if ((adts_channel_configuration < 0) || (adts_channel_configuration > 7))
    return AAC_BAD_PARAMETER;

  state->com.adts_channel_configuration = adts_channel_configuration;
  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecInitCRC(Ipp32s crc_enable,
                         AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  bs_CRC_reset((Ipp32u*)&state->com.crc);
  state->com.crc_enable = crc_enable;
  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecSetCRC(Ipp32s crc,
                        AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  state->com.crc = crc;
  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecGetCRC(Ipp32s *crc,
                        AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  if (!crc)
    return AAC_NULL_PTR;

  *crc = state->com.crc;
  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecGetSbrFlagPresent(Ipp32s *SbrFlagPresent,
                                   AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  *SbrFlagPresent = state->com.SbrFlagPresent;
  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecGetFrameSize(Ipp32s *frameSize,
                              AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  *frameSize = state->com.m_frame_size * state->com.m_up_sample;
  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecGetSampleFrequency(Ipp32s *freq,
                                    AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  *freq = state->com.m_sampling_frequency * state->com.m_up_sample;
  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecGetNumDecodedFrames(Ipp32s *num,
                                     AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  *num = state->com.m_frame_number;
  return AAC_OK;
}


/********************************************************************/

AACStatus aacidecGetChannels(Ipp32s *ch,
                             AACDec *state)
{
  if (!state)
    return AAC_NULL_PTR;

  *ch = state->com.m_channel_number;
  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecGetInfo(cAudioCodecParams *a_info,
                         AACDec *state)
{
  if (!a_info)
    return AAC_NULL_PTR;

  a_info->m_SuggestedInputSize = CH_MAX * 768;
  a_info->m_SuggestedOutputSize = CH_MAX * 1024 * 2 /* upsampling SBR */ * sizeof(Ipp16s);
  a_info->is_valid = 0;

  if (!state)
    return AAC_OK;

  if (state->com.m_frame_number > 0) {
    a_info->m_info_in.bitPerSample = 0;
    a_info->m_info_out.bitPerSample = 16;

    a_info->m_info_in.bitrate = 0;
    a_info->m_info_out.bitrate = 0;

    a_info->m_info_in.channels = state->com.m_channel_number;
    a_info->m_info_out.channels = state->com.m_channel_number;

    a_info->m_info_in.sample_frequency = state->com.m_sampling_frequency;
    a_info->m_info_out.sample_frequency = state->com.m_sampling_frequency * state->com.m_up_sample;

    a_info->m_info_in.stream_type = AAC_AUD;
    a_info->m_info_out.stream_type = PCM_AUD;

    a_info->m_frame_num = state->com.m_frame_number;

    a_info->is_valid = 1;

    return AAC_OK;
  }

  return AAC_OK;
}

/********************************************************************/

AACStatus aacidecGetDuration(Ipp32f *p_duration,
                             AACDec *state)
{
  Ipp32f  duration;

  duration = (Ipp32f)(state->com.m_frame_number) * 1024;
  *p_duration = duration / (Ipp32f)(state->com.m_sampling_frequency);

  return AAC_OK;
}

/********************************************************************/

AACStatus aacidec_GetID3Len(Ipp8u  *in,
                            Ipp32s inDataSize,
                            AACDec *state)
{
  if (state->com.FirstID3Search != 0)
    return AAC_OK;

  if (inDataSize < 10)
    return AAC_NOT_ENOUGH_DATA;

  if ((in[0] == 'I') && (in[1] == 'D') && (in[2] == '3') && /* 'ID3' */
      (in[3] < 0xFF) && (in[4] < 0xFF) &&                   /* Version or revision will never be 0xFF */
      (in[6] < 0x80) && (in[7] < 0x80) && (in[8] < 0x80) && (in[9] < 0x80)) { /* size */
    state->com.id3_size = (in[6] << 21) + (in[7] << 14) + (in[8] << 7) + in[9] +
      (in[5] & 0x10 ? 20 : 10);
  } else {
    state->com.id3_size = 0;
  }

  state->com.FirstID3Search = 1;

  return AAC_OK;
}

/********************************************************************/

AACStatus aacidec_SkipID3(Ipp32s inDataSize,
                          Ipp32s *skipped,
                          AACDec *state)
{
  *skipped = 0;
  if (state->com.id3_size > 0) {
    if (inDataSize < state->com.id3_size) {
      *skipped = inDataSize;
      state->com.id3_size -= inDataSize;
      return AAC_NOT_ENOUGH_DATA;
    } else {
      *skipped = state->com.id3_size;
      state->com.id3_size = 0;
      return AAC_OK;
    }
  }
  return AAC_OK;
}

/********************************************************************/

#endif //UMC_ENABLE_AAC_INT_AUDIO_DECODER


